package com.ubxtech.core.context;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.ubxtech.core.utils.StrPool;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Victor.Xiao
 * @since 2022-01-07 19:23
 **/
public final class ContextUtil {
    private ContextUtil() {
    }

    private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new ThreadLocal<>();
//    /**
//     * 支持多线程传递参数
//     */
//    private static final ThreadLocal<Map<String, String>> THREAD_LOCAL = new TransmittableThreadLocal<>();

    public static void putAll(Map<String, Object> map) {
        map.forEach(ContextUtil::set);
    }

    public static void set(String key, Object value) {
        Map<String, Object> map = getLocalMap();
        map.put(key, value == null ? StrPool.EMPTY : value);
    }

    public static <T> T get(String key, Class<T> type, T defaultObj) {
        Map<String, Object> map = getLocalMap();
        return Convert.convert(type, map.getOrDefault(key,defaultObj));
    }
    public static <T> T get(String key, Class<T> type) {
        Map<String, Object> map = getLocalMap();
        return Convert.convert(type, map.get(key));
    }

    public static Object get(String key) {
        Map<String, Object> map = getLocalMap();
        return map.getOrDefault(key, StrPool.EMPTY);
    }

    public static Map<String, Object> getLocalMap() {
        Map<String, Object> map = THREAD_LOCAL.get();
        if (map == null) {
            map = new ConcurrentHashMap<>(10);
            THREAD_LOCAL.set(map);
        }
        return map;
    }

    public static void setLocalMap(Map<String, Object> localMap) {
        THREAD_LOCAL.set(localMap);
    }


    public static String getXTraceId() {
        return get(ContextConstants.X_TRACE_ID, String.class, "");
    }

    /**
     * 日志id
     */
    public static void setXTraceId(String traceId) {
        set(ContextConstants.X_TRACE_ID, traceId);
    }

    public static String getPTraceId() {
        return get(ContextConstants.P_TRACE_ID, String.class, "");
    }

    /**
     * 日志id
     */
    public static void setPTraceId(String traceId) {
        set(ContextConstants.P_TRACE_ID, traceId);
    }


    /**
     * 获取token
     *
     * @return token
     */
    public static ContextToken getContextToken() {
        return get(ContextConstants.CONTEXT_TOKEN, ContextToken.class,new ContextToken());
    }

    public static void setContextToken(ContextToken token) {
        set(ContextConstants.CONTEXT_TOKEN, token);
        if (StrUtil.isNotBlank(token.getTenant())) {
            setTenant(token.getTenant());
        }
    }


    public static String getClientId() {
        return get(ContextConstants.CLIENT_ID, String.class);
    }

    public static void setClientId(String val) {
        set(ContextConstants.CLIENT_ID, val);
    }

    /** 获取多租户值 */
    public static String getTenant() {
        ContextToken contextToken = getContextToken();
        if (contextToken == null) {
            return get(ContextConstants.KEY_TENANT, String.class, "");
        }

        if (StrUtil.isBlank(contextToken.getTenant())) {
            String tenant = get(ContextConstants.KEY_TENANT, String.class, "");
            contextToken.setTenant(tenant);
            return tenant;
        }
        return contextToken.getTenant();
    }

    public static void setTenant(String val) {
        set(ContextConstants.KEY_TENANT, val);
    }


    /** 是否忽略多租户 */
    public static Boolean getIgnoreTenantFlag() {
        return get(ContextConstants.KEY_IGNORE_TENANT_FLAG, Boolean.class, false);
    }

    public static void setIgnoreTenantFlag(boolean val) {
        set(ContextConstants.KEY_IGNORE_TENANT_FLAG, val);
    }

    public static void remove(String key) {
        Map<String, Object> map = getLocalMap();
        map.remove(key);
    }

    public static void remove() {
        THREAD_LOCAL.remove();
    }

    public static <T> T mapToBean(Class<T> clazz) {
        CopyOptions copyOptions = new CopyOptions();
        copyOptions.setIgnoreError(true);
        return BeanUtil.mapToBean(getLocalMap(),clazz,true,copyOptions);
    }


    /** 设置灰度版本 */
    public static void setGrayVersion(String version) {
        set(ContextConstants.HEADER_GRAY_VERSION_NAME, version);
    }

    /** 获取灰度版本 */
    public static String getGrayVersion() {
        return get(ContextConstants.HEADER_GRAY_VERSION_NAME, String.class,"");
    }
}
